from math import sqrt

import adjustment_curve
import config
import longitudinal_graph
from adjustment_curve import getxy, get_location
from longitudinal_graph import getZ

"""
里程区间是-1600到410
中间涉及5段曲线
每一段的超高在超高.txt中有显示
还有道床厚度（起始里程、结束里程、道床厚度）

1和2之前就是第一段缓和曲线
2和3之前啊就是圆弧
3和4之间是第二段缓和曲线
"""
"""
里程属于：
1. 直线
    超高为0
2. 前缓和曲线
    读超高：0到超高线性递增
3. 圆弧
    读超高
4. 后缓和曲线
    读超高：超高到0线性递减
读道床高度
算出圆心坐标 (0, R - bed_height)
算偏移 X'= (R - bed_height) * h/1506
偏移圆心 (X', R - bed_height)
画出圆 (x - X')^2 + (y - R + bed_height)^2 = R^2
"""


class DesignOutlineDrawer:
    curves = []
    beds = []
    hs = []

    def __init__(self, R, h_file_path, bed_file_path, _s):
        # write_s_file()
        self.R = R  # 半径
        self._s = _s  # 滚动圆间距
        self.read_file(h_file_path, bed_file_path)
        self.update_curves()

    def read_file(self, h_file_path, bed_file_path):
        """从文件里读道床高度和超高"""
        self.beds = []
        self.hs = []
        with open(h_file_path) as h_file, open(bed_file_path) as bed_file:
            for line in bed_file:
                bed_info = line.split(',')
                self.beds.append({
                    'start': float(bed_info[0]),
                    'end': float(bed_info[1]),
                    'bed_height': float(bed_info[2])
                })
            for line in h_file:
                self.hs += [float(i) for i in line.split(',')]

    def update_curves(self, x=None, y=None, r=None, len1=None, len2=None, x1=None, y1=None, r1=None):
        """
        更新路线。如果传入的是None则从文件里读取
        :param x: x数组
        :param y: y数组
        :param r: r数组
        :param len1: 前缓和len1数组
        :param len2: 后缓和len2数组
        """

        self.curves.clear()
        if x is not None:
            adjustment_curve.units1_2 = adjustment_curve.get_the_route(x, y, r, len1, len2)
            longitudinal_graph.units2_2 = longitudinal_graph.get_the_route(x1, y1, r1)

        adjustment_curve.units1_2.sort(key=lambda u: u.start_s)
        j = 0
        the_s = get_location()
        for unit in adjustment_curve.units1_2:
            s = unit.start_s - the_s + config.begin_s
            bed_height = -1
            for bed in self.beds:
                if bed['start'] < s < bed['end']:
                    bed_height = bed['bed_height']
            if bed_height < 0:
                continue

            curve_map = {
                'line': [0, 4, j + 1],  # 直线
                'ftc': [0, 1, j],  # 前缓和曲线
                'circle': [self.hs[j], 2, j],  # 圆弧
                'btc': [self.hs[j], 3, j]  # 后缓和曲线
            }
            h, _type, j = curve_map[unit.type]
            self.curves.append({
                '_type': _type,
                'h': h,
                's': s,
                'bed_height': bed_height
            })

    def find_curve(self, s):
        """:return: [超高, 道床高度]"""
        for i in range(len(self.curves)):
            if self.curves[i]['s'] > s:
                curve1 = self.curves[i - 1]
                curve2 = self.curves[i]
                s1, s2, h1, h2 = curve1['s'], curve2['s'], curve1['h'], curve2['h']
                # if h1 > h2:
                #     h1, h2 = h2, h1
                if curve1['_type'] == 3:
                    return [-((s - s1) / (s2 - s1) * (h2 - h1) + h1), curve1['bed_height']]
                else:
                    return [(s - s1) / (s2 - s1) * (h2 - h1) + h1, curve1['bed_height']]

    def draw_outline(self, s):
        """:return: 圆心坐标"""
        h, bed_height = self.find_curve(s)
        X = bed_height * h / self._s
        y = bed_height
        return [X, y]

    def calculate_coordinate_by_x(self, s, x):
        x0, y0 = self.draw_outline(s)
        flag = getxy(s,2)[-1]
        x0 *= flag
        # draw_circle(x0, y0, self.R)
        y0 = getZ(s, 2) * 1000 + y0
        x *= 1000
        # print('(x - {})^2 + (y - {})^2 = {}'.format(x0, y0, self.R * self.R))
        return [sqrt(self.R * self.R - pow((x - x0), 2)) + y0, -sqrt(self.R * self.R - pow((x - x0), 2)) + y0]

    def calculate_coordinate_by_y(self, s, y, add_Z=True):
        x0, y0 = self.draw_outline(s)
        flag = getxy(s,2)[-1]
        x0 *= flag
        # print('左转' if flag < 0 else '右转')
        # draw_circle(x0, y0, self.R)
        if add_Z:
            y0 += getZ(s,2) * 1000
        y *= 1000
        # print('(x - {})^2 + (y - {})^2 = {}'.format(x0, y0, self.R * self.R))
        return [sqrt(self.R * self.R - pow((y - y0), 2)) + x0, -sqrt(self.R * self.R - pow((y - y0), 2)) + x0]
        # if flag < 0:
        #     return [sqrt(self.R * self.R - pow((y - y0), 2)) + x0, -sqrt(self.R * self.R - pow((y - y0), 2)) + x0]
        # else:
        #     return [-sqrt(self.R * self.R - pow((y - y0), 2)) + x0, sqrt(self.R * self.R - pow((y - y0), 2)) + x0]


def write_s_file():
    adjustment_curve.units1_2.sort(key=lambda unit: unit.start_s)
    with open(config.s_file_path, 'w') as s_file:
        for i in range(len(adjustment_curve.units1_2)):
            if adjustment_curve.units1_2[i].type == 'ftc':
                s_file.write('1')
            elif adjustment_curve.units1_2[i].type == 'circle':
                s_file.write('2')
            elif adjustment_curve.units1_2[i].type == 'btc':
                s_file.write('3')
            elif adjustment_curve.units1_2[i].type == 'line':
                s_file.write('4')
            the_s = get_location()
            dif = adjustment_curve.units1_2[i].start_s - the_s
            s_file.write(' {}\n'.format(dif + config.begin_s))


if __name__ == '__main__':
    s = -1583.5  # 里程
    y = -8.11  # 点的y坐标

    dod = DesignOutlineDrawer(config.section_R, config.h_file_path, config.bed_file_path, config.circle_s)
    # print(dod.draw_outline(s))
    x1, x2 = dod.calculate_coordinate_by_y(s, y)  # 根据y计算x
    y1, y2 = dod.calculate_coordinate_by_x(s, 0)  # 根据x计算y
    print(x1, x2, y1, y2)
